/* * Copyright (c) 2013-2014, Pierre Laporte * * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3 only, as * published by the Free Software Foundation. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. * * You should have received a copy of the GNU General Public License * along with this work; if not, see <http://www.gnu.org/licenses/>. */ package fr.pingtimeout.tyrion.agent; import fr.pingtimeout.tyrion.transformation.CriticalSectionsInterceptor; import fr.pingtimeout.tyrion.util.EventsWriter; import fr.pingtimeout.tyrion.util.SimpleLogger; import java.io.FileOutputStream; import java.io.IOException; import java.lang.instrument.Instrumentation; import java.nio.charset.Charset; import java.util.concurrent.Executors; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.ThreadFactory; import java.util.concurrent.TimeUnit; public class LockProfilingAgent { /** * JVM hook to statically load the javaagent at startup. * <p/> * After the Java Virtual Machine (JVM) has initialized, the premain method * will be called. Then the real application main method will be called. * * @param args The agent's arguments * @param inst The instrumentation class that will be used * @throws Exception */ public static void premain(String args, Instrumentation inst) throws Exception { Configuration configuration = new Configuration(args); Configuration.ParameterValue outputFileParameter = configuration.outputFile(); if (outputFileParameter.isDefaultValue()) { SimpleLogger.warn("No output file was provided, agent is disabled"); } else { SimpleLogger.info("Tyrion agent starting with arguments '%s'", configuration); final String outputFile = outputFileParameter.getValue(); clearOutputFile(outputFile); scheduleLocksWrite(outputFile); configureLockInterceptor(configuration); instrumentLocks(inst); } } private static void clearOutputFile(String outputFile) { try (FileOutputStream erasor = new FileOutputStream(outputFile)) { erasor.write("".getBytes(Charset.forName("UTF-8"))); } catch (IOException e) { SimpleLogger.warn("Output file could not be cleared. Cause : %s", e.getMessage()); SimpleLogger.debug(e); } } private static void instrumentLocks(Instrumentation inst) { inst.addTransformer(new CriticalSectionsInterceptor()); } private static void scheduleLocksWrite(String outputFile) { final ScheduledExecutorService executorService = Executors.newScheduledThreadPool(1, new ThreadFactory() { @Override public Thread newThread(Runnable r) { Thread t = new Thread(r, EventsWriter.THREAD_NAME); t.setDaemon(true); return t; } }); executorService.scheduleAtFixedRate(new EventsWriter(outputFile), 1, 1, TimeUnit.SECONDS); } private static void configureLockInterceptor(Configuration configuration) { LockInterceptor lockInterceptor = LockInterceptor.getInstance(); Configuration.ParameterValue excludedThreadsParam = configuration.excludedThreads(); for (String excludedThreadName : excludedThreadsParam.getValues()) { lockInterceptor.addExcludedThread(excludedThreadName); } String enabledAtStartup = configuration.isEnabledAtStartup().getValue(); if (Boolean.valueOf(enabledAtStartup)) { lockInterceptor.setEnabled(true); } } }